package com.ny.zmb.openapi.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.ny.zmb.openapi.config.YsConfig;
import org.apache.commons.lang.StringUtils;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 银盛工具类封装
 */
@Service
public class YsUtil {
    //测试 https://appdev.ysepay.com
    //生产 https://ysgate.ysepay.com
    /**
     * 发起方商户号 服务商在银盛给自己开设的商户号，即可当作发起方商户号
     * 生产环境需要使用自己的发起发商户号，并找相应的对接人员开通所需要的接口权限，并告知是国密还是RSA
     */
    private static final String CERT_ID = "826513173750017";

    private static final String ALLCHAR = "0123456789ABCDEF";

    /**
     * 银盛端公钥证书
     * 生产环境需要自行去开放平台上下载银盛公钥证书，也可以找对接人提供
     */

    private String YS_PUBLIC_CER_PATH = new YsConfig().getYsPublicCerPath();

    /**
     * 商户端私钥证书
     * 生产环境需要使用自己生产的私钥证书
     */
    private String MERC_PRIVATE_FILE = new YsConfig().getMercPrivateFile();
    /**
     * 商户端私钥证书密码
     * 生产环境需要使用自己私钥的密码
     */
    private static final String MERC_PRIVATE_FILE_PASSWORD = "197Aa2569";

    public Map<String, String> resultMap(String keyValue, Object value, Map<String, Object> addMap,String method) throws Exception {
        /** 1、封装请求参数，bizContent（业务参数，需要加密）和chec（需要生成密钥并加密）后面设置值*/
        Map<String, String> reqMap = new HashMap<String, String>();
        reqMap.put("method", method);
        reqMap.put("timeStamp", getCurrentDateTime("yyyy-MM-dd HH:mm:dd"));
        reqMap.put("charset", "utf-8");
        reqMap.put("reqId", String.valueOf(System.currentTimeMillis()));
        reqMap.put("certId", CERT_ID);//测试环境可以用这个
        reqMap.put("version", "1.0");

        /** 2、生成对业务参数加密的密钥*/
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 16; i++) {
            sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
        }
        String key = ByteUtil.toHexString(sb.toString());

        /** 3、使用银盛公钥对密钥key进行加密，得到加密的key并设置到请求参数check中。publicFilePath为存放银盛公钥的地址*/
        String check = GMSignUtils.encryptData(YS_PUBLIC_CER_PATH, key);
        reqMap.put("check", check);//加密后的密钥

        /** 4、封装业务参数,具体参数见文档，这里只是举例子*/
        Map<String, Object> bizContentMap = new HashMap<>();
        //商户号，此商户号一定要是该发起发下的商户号
        bizContentMap.put(keyValue, value);
        if (null != addMap) {
            bizContentMap.putAll(addMap);
        }

        /** 5、使用生成的密钥key对业务参数进行加密，并将加密后的业务参数放入请求参数bizContent中*/
        JSONObject bizJSONObj = JSONObject.parseObject(JSON.toJSONString(bizContentMap));
        byte[] bte = AESUtil.encrypt(JSONObject.toJSONBytes(bizJSONObj, SerializerFeature.WriteNullStringAsEmpty), ByteUtil.hexStringToBytes(key));
        String msgBizConten = Base64.encodeBase64String(bte);
        reqMap.put("bizContent", msgBizConten);

        /** 6、将请求参数进行sort排序，生成拼接的字符床，并使用接入方私钥对请求参数进行加签，并将加签的值存入请求参数sign中*/
        //6.1 排序生成拼接字符串
        List<String> keys = new ArrayList<String>(reqMap.keySet());
        Collections.sort(keys);
        StringBuilder sb1 = new StringBuilder();
        for (String k : keys) {
            if ("sign".equals(k)) {
                continue;
            }
            sb1.append(k).append("=");
            sb1.append(reqMap.get(k));
            sb1.append("&");
        }
        if (sb1.length() > 0) {
            sb1.setLength(sb1.length() - 1);
        }
        //6.2使用接入方私钥对排序的请求参数加签，并存放到请求参数里面.privateFilePath:私钥地址，prvatePassword:私钥密钥
        String sign = GMSignUtils.signMsgSM2(MERC_PRIVATE_FILE, MERC_PRIVATE_FILE_PASSWORD, sb1.toString());
        reqMap.put("sign", sign);
        reqMap.put("resultKey", key);
        return reqMap;
    }

    /**
     * 格式化当前日期时间字符串
     *
     * @return
     */
    private static String getCurrentDateTime(String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(new Date());
    }

}